Skip to content

test/syscalls,g3doc: add journaled overlay test variants and user guide - #17153

Draft
manninglucas wants to merge 1 commit into
lucasmanning/tmpfs-journal-20-boot-restorefrom
lucasmanning/tmpfs-journal-poc
Draft

manninglucas wants to merge 1 commit into
lucasmanning/tmpfs-journal-20-boot-restorefrom
lucasmanning/tmpfs-journal-poc

Conversation

@manninglucas

@manninglucas manninglucas commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

Add the --journaled-overlay test runner mode and add_journaled_overlay
Starlark parameter (enabled on mmap_test and utimes_test), and document
journaling rootfs uppers alongside checkpoint/restore, filesystem
snapshots, and rootfs tar snapshots.

Stack

  1. pgalloc: support adopting existing pages and unsaved reservations #17592 — pgalloc: support adopting existing pages and unsaved reservations (+531 / -3)
  2. tmpfs/journal: add journal header format, Create, and Close #17593 — tmpfs/journal: add journal header format, Create, and Close (+510 / -0)
  3. tmpfs/journal: add Open header validation and page adoption #17594 — tmpfs/journal: add Open header validation and page adoption (+331 / -5)
  4. tmpfs/journal: add record schema, State types, and SnapshotSizer #17595 — tmpfs/journal: add record schema, State types, and SnapshotSizer (+289 / -17)
  5. tmpfs/journal: add binary record encoding and Snapshot writer #17596 — tmpfs/journal: add binary record encoding and Snapshot writer (+493 / -7)
  6. tmpfs/journal: decode and replay snapshot records #17597 — tmpfs/journal: decode and replay snapshot records (+487 / -3)
  7. tmpfs/journal: add live mutation writers and delta replay #17598 — tmpfs/journal: add live mutation writers and delta replay (+469 / -2)
  8. tmpfs/journal: add incomplete journal state and recovery/validation tests #17599 — tmpfs/journal: add incomplete journal state and recovery/validation tests (+445 / -0)
  9. tmpfs/journal: expose FilestoreEnd high-water mark for shrinking #17600 — tmpfs/journal: expose FilestoreEnd high-water mark for shrinking (+321 / -2)
  10. tmpfs: rebuild filesystem state from a replayed journal #17601 — tmpfs: rebuild filesystem state from a replayed journal (+452 / -1)
  11. tmpfs: add journal snapshot compaction and release lifecycle #17602 — tmpfs: add journal snapshot compaction and release lifecycle (+444 / -43)
  12. tmpfs: journal live namespace, inode, and extent mutations #17603 — tmpfs: journal live namespace, inode, and extent mutations (+398 / -3)
  13. tmpfs: add background compactor, save/restore hooks, and self-whiteout sync #17604 — tmpfs: add background compactor, save/restore hooks, and self-whiteout sync (+258 / -1)
  14. tmpfs,overlay: support activating journaling on populated filesystems #17605 — tmpfs,overlay: support activating journaling on populated filesystems (+492 / -1)
  15. runsc/config: add journaling rootfs upper flags and policy enums #17606 — runsc/config: add journaling rootfs upper flags and policy enums (+161 / -0)
  16. runsc/specutils: add journaling rootfs upper annotations and resolution #17607 — runsc/specutils: add journaling rootfs upper annotations and resolution (+401 / -2)
  17. runsc/container: manage, lock, and shrink journaled rootfs filestores #17608 — runsc/container: manage, lock, and shrink journaled rootfs filestores (+403 / -7)
  18. runsc/boot: wire fresh and imported journaling rootfs uppers #17609 — runsc/boot: wire fresh and imported journaling rootfs uppers (+483 / -43)
  19. runsc/boot: activate journaling uppers populated by tar or fs-restore #17610 — runsc/boot: activate journaling uppers populated by tar or fs-restore (+500 / -4)
  20. runsc/boot: activate journaling uppers on checkpoint restore #17611 — runsc/boot: activate journaling uppers on checkpoint restore (+516 / -2)
  21. test/syscalls,g3doc: add journaled overlay test variants and user guide #17153 — test/syscalls,g3doc: add journaled overlay test variants and user guide (+195 / -2) (this PR)

Full Stack Overview

Adds metadata journaling for a container's file-backed rootfs overlay upper tmpfs layer (--journaling-rootfs-upper and --journaling-rootfs-upper-import), storing both the metadata journal and regular-file data pages in the single rootfs upper filestore pgalloc.MemoryFile so a new sandbox can rebuild the upper layer after a sentry crash (SIGKILL / panic) or clean stop without copying file data.

How it works

  • Single-file layout (pkg/sentry/pgalloc, pkg/sentry/fsimpl/tmpfs/journal): Page 0 of the backing filestore holds a 4 KiB journal header (build ID, image ID, active generation/flags, filestoreEnd high-water mark, and two region descriptors). Two dynamically sized journal regions are allocated in the same pgalloc.MemoryFile via unsaved page reservations (ClaimFirstPageUnsaved, AllocateUnsaved, FreeUnsaved), which are excluded from memory accounting and checkpoint SaveTo metadata.
  • Append & compaction (pkg/sentry/fsimpl/tmpfs): tmpfs appends records to a MAP_SHARED mapping of the active region for namespace, attribute, xattr/ACL, and regular-file extent mutations. Records that drop extents are appended before pages are freed. Compaction writes a snapshot to the inactive region (relocating/growing it if needed) and flips the active region with one atomic generation store, and is stopped across PrepareSave and BeforeResume so it never mutates MemoryFile during SaveTo.
  • Untrusted replay & in-place page adoption: journal.Open stops at the first torn tail record, verifies directory tree reachability and extent disjointness, and calls MemoryFile.AdoptExisting to adopt referenced data extents in place while punching holes over unused ranges so free pages remain zeroed. When keepJournal is false, Open frees the unsaved header and active region pages so subsequent unjournaled writes cannot leave a stale importable journal.
  • Unjournaled path: When journaling is off, metadata hooks check a single nil pointer (fs.journal.Load()), and regular-file allocation/truncation/release paths track whether any regular file holds MemoryFile offset 0 (fs.pageZeroOwner, guarding CompareAndSwap in inode.decRef behind a pointer load) so PrepareJournal can relocate page 0 when activating journaling on an already-populated tmpfs.

Interface

  • Runtime journaling: --journaling-rootfs-upper=on for the root container, or (with --journaling-rootfs-upper-annotations=on) dev.gvisor.journal.rootfs.upper: "true" per container (.<container-name> in multi-container pods). Requires a file-backed rootfs overlay such as --overlay2=root:self (the default) or --overlay2=root:dir=<dir>. With root:self, the combined journal+filestore lives at <rootfs>/.gvisor.filestore.<sandbox-id>, hidden from the container by an upper-layer whiteout without modifying / timestamps, locked with an exclusive flock, and preserved by Container.Destroy so external tooling can extract or re-import it.
  • Startup import / replay: --journaling-rootfs-upper-import=<path-or-/proc/self/fd/N> or (with --journaling-rootfs-upper-annotations=on) dev.gvisor.journal.rootfs.upper.import[.<name>] (procfs/devfd paths are accepted via the CLI flag only). Works independently of runtime journaling:
    • With runtime journaling enabled and root:self, runsc hardlinks the imported file to <rootfs>/.gvisor.filestore.<new-sandbox-id> (falling back to the imported FD directly across mounts) and continues journaling in place.
    • With runtime journaling disabled, tmpfs replays and adopts the imported filestore in place, clears the journal header/region, and runs unjournaled.
  • Optional image ID verification: --journaling-rootfs-upper-image-id and (with --journaling-rootfs-upper-annotations=on) dev.gvisor.journal.rootfs.upper.image-id[.<name>] optionally record the lower image identity on creation and verify it on import when non-empty; when omitted on import (the default), image ID verification is skipped.
  • Checkpoint / snapshot interop: Checkpoints, filesystem checkpoints, and rootfs upper tar archives work in both directions. Checkpoints of a journaled container omit unsaved journal pages and restore with or without journaling; populating a new journaled container via restore, --fs-restore-image-path, or dev.gvisor.tar.rootfs.upper hides any self-backed filestore before tasks start, runs PrepareJournal (relocating any regular-file page at offset 0 and writing incompleteBit) followed by ActivateJournal once population completes, and waits for pending activation before reporting a clean 0 container exit. --journaling-rootfs-upper-import is refused alongside restore, filesystem restore, or rootfs upper tar.
  • Docs: g3doc/user_guide/checkpoint_restore.md compares checkpoint/restore, filesystem snapshots, rootfs tar snapshots, and the journaling rootfs upper.

Benchmarks

Interleaved n=16 before vs. after on unjournaled tmpfs (//pkg/sentry/fsimpl/tmpfs:tmpfs_test and //pkg/sentry/fsimpl/tmpfs:benchmark_test), showing no statistically significant change when journaling is off:

goos: linux
goarch: amd64
cpu: Intel(R) Xeon(R) CPU @ 2.20GHz
                              │  before.txt  │              after.txt               │
                              │    sec/op    │    sec/op      vs base               │
DiskBackedWrite/size=64-16      835.4n ± 17%    814.4n ±  9%       ~ (p=0.838 n=16)
DiskBackedWrite/size=4096-16    957.7n ±  7%   1003.5n ± 12%       ~ (p=0.200 n=16)
DiskBackedWrite/size=32768-16   2.711µ ±  8%    2.592µ ±  9%       ~ (p=0.491 n=16)
TmpfsStat/1-16                  518.8n ± 12%    520.5n ±  5%       ~ (p=0.669 n=16)
TmpfsStat/8-16                  1.135µ ±  7%    1.124µ ± 12%       ~ (p=0.933 n=16)
geomean                         1.050µ          1.044µ        -0.59%

                              │  before.txt   │              after.txt               │
                              │      B/s      │      B/s       vs base               │
DiskBackedWrite/size=64-16      73.07Mi ±  9%   74.97Mi ± 11%       ~ (p=0.838 n=16)
DiskBackedWrite/size=4096-16    3.984Gi ± 10%   3.802Gi ± 14%       ~ (p=0.196 n=16)
DiskBackedWrite/size=32768-16   11.26Gi ±  6%   11.78Gi ± 10%       ~ (p=0.491 n=16)
geomean                         1.474Gi         1.485Gi        +0.80%

Per-operation journaling overhead (BenchmarkJournalCreateWriteUnlink, n=16, journaled=false vs. journaled=true for OpenAt(O_CREAT) + 4 KiB PWrite + Close + UnlinkAt, appending 7 CRC32C-checked records to the MAP_SHARED active region):

goos: linux
goarch: amd64
cpu: Intel(R) Xeon(R) CPU @ 2.20GHz
                            │    false    │                true                 │
                            │   sec/op    │   sec/op     vs base                │
JournalCreateWriteUnlink-16   7.338µ ± 5%   9.668µ ± 4%  +31.75% (p=0.000 n=16)

Enabling journaling adds ~2.33µs across the full create + 4 KiB write + unlink cycle (~330ns per appended metadata record).

Testing

  • //pkg/sentry/pgalloc:pgalloc_test (AdoptExisting, hole-punching, unsaved exclusions across SaveTo/LoadFrom)
  • //pkg/sentry/fsimpl/tmpfs/journal:journal_test (round-trip, keepJournal=false header/region clearing, torn tail recovery, compaction, region relocation, FilestoreEnd shrinking, untrusted input validation)
  • //pkg/sentry/fsimpl/tmpfs:tmpfs_test (crash/rebuild model comparison, unjournaled import, concurrent compaction, page-0 relocation on PrepareJournal + ActivateJournal)
  • //runsc/config:config_test, //runsc/specutils:specutils_test, //runsc/boot:boot_test, //runsc/container:container_test (TestJournalingRootfsUpper*: SIGKILL & clean exit persistence, /proc/self/fd/N import, unjournaled import, optional image ID verification, --journaling-rootfs-upper-annotations gating, flock contention, FilestoreEnd shrink verification, bidirectional checkpoint/fs-checkpoint/tar interop, fast-exit activation synchronization, activation fault injection, multi-container pods, overlay validation)
  • _overlay_journal, _overlay_journal_save, and _overlay_journal_save_resume syscall test variants

@manninglucas
manninglucas force-pushed the lucasmanning/tmpfs-journal-poc branch from 74c12d9 to bedd3e4 Compare November 7, 2026 00:12
@milantracy

Copy link
Copy Markdown
Collaborator

cc: @ayushr2 we chat about the journaling, and you may have some experience on it

@manninglucas
manninglucas force-pushed the lucasmanning/tmpfs-journal-poc branch 4 times, most recently from 543a133 to 0d27653 Compare November 12, 2026 22:30
@manninglucas manninglucas changed the title runsc: add --journaling-rootfs-upper runsc: add --journaling-rootfs-upper and --journaling-rootfs-upper-import Nov 12, 2026
@EtiennePerot

Copy link
Copy Markdown
Collaborator

What is the impetus for this? I understand the benefit but curious who's asking for this feature.

@manninglucas

Copy link
Copy Markdown
Contributor Author

@EtiennePerot there's interest from those running large RL-style workflows to have smoother recovery when there's a sandbox crash. They don't need to recover application state, but they want the filesystem to at least have all their changes from "boot" up until when the crash happened. This way they can tell agents "sorry your computer crashed, but all your files are still in place, please continue where you left off" when crashes happen during training.

@manninglucas
manninglucas force-pushed the lucasmanning/tmpfs-journal-poc branch from 0d27653 to c4318bf Compare November 13, 2026 00:04
Add the --journaled-overlay test runner mode and add_journaled_overlay
Starlark parameter (enabled on mmap_test and utimes_test), and document
journaling rootfs uppers alongside checkpoint/restore, filesystem
snapshots, and rootfs tar snapshots.
@manninglucas
manninglucas force-pushed the lucasmanning/tmpfs-journal-poc branch from c4318bf to d6eead7 Compare November 13, 2026 01:52
@manninglucas manninglucas changed the title runsc: add --journaling-rootfs-upper and --journaling-rootfs-upper-import test/syscalls,g3doc: add journaled overlay test variants and user guide Nov 13, 2026
@manninglucas
manninglucas changed the base branch from master to lucasmanning/tmpfs-journal-20-boot-restore November 13, 2026 01:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants